package net.tyw.web.ctrl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import net.tyw.common.JSONResult;
import net.tyw.common.encry.Token;
import net.tyw.common.utils.DateUtil;
import net.tyw.common.utils.RandCodeUtil;
import net.tyw.common.utils.ValidateUtil;
import net.tyw.core.auth.Oauth;
import net.tyw.core.auth.OauthService;
import net.tyw.core.auth.OauthUser;
import net.tyw.core.enums.oauth.UserLoginAccountType;
import net.tyw.core.enums.oauth.UserPasswdType;
import net.tyw.core.model.oauth.*;
import net.tyw.core.service.oauth.UserInfoService;
import net.tyw.web.params.LoginParam;
import net.tyw.web.params.ModifyPasswordParam;
import net.tyw.web.servlet.ServletContext;
import net.tyw.web.servlet.ServletUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.*;

@Controller
public class OauthCtrl {

    private final static Logger logger = LoggerFactory.getLogger(OauthCtrl.class);

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private OauthService oauthService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Oauth
    @ResponseBody
    @RequestMapping("/oauth/role/delete")
    public JSONResult deleteRole(@RequestBody String stringRoleIds) {
        try {
            logger.debug(JSON.toJSONString(stringRoleIds));
            List<Long> listRoleIds = JSON.parseArray(stringRoleIds, Long.class);
            this.userInfoService.deleteRole(listRoleIds);
            return JSONResult.instance().setData(true);
        } catch (Exception e) {
            logger.error("delete role", e);
            return JSONResult.instance("system_error", "系统忙，请稍后再试");
        }
    }

    @Oauth
    @ResponseBody
    @RequestMapping("/oauth/role/save")
    public JSONResult saveRole(@RequestBody String paramsString) {
        try {
            JSONObject jsonObject = JSON.parseObject(paramsString);
            RoleInfo roleInfo = jsonObject.getObject("roleInfo", RoleInfo.class);
            List<Long> listResourceIds = new ArrayList<>();
            if (StringUtils.isNotBlank(jsonObject.getString("resourceIds"))) {
                listResourceIds = JSON.parseArray(jsonObject.getString("resourceIds"), Long.class);
            }

            this.userInfoService.saveRole(roleInfo, listResourceIds);
            return JSONResult.instance().setData(true);
        } catch (Exception e) {
            logger.error("save role", e);
            return JSONResult.instance("system_error", "系统忙，请稍后再试");
        }
    }

    @Oauth
    @ResponseBody
    @RequestMapping("/oauth/role/findById")
    public JSONResult findRoleById(@RequestBody Map<String, Long> param) {
        RoleInfo roleInfo = this.userInfoService.findRoleById(param.get("roleId"));
        List<Resource> listResource = this.userInfoService.findResourceByRole(param.get("roleId"));

        List<Long> hasResource = new ArrayList<>();
        if (listResource != null && listResource.size() > 0) {
            for (Resource resource : listResource) {
                hasResource.add(resource.getId());
            }
        }
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("hasResource", hasResource);
        dataMap.put("roleInfo", roleInfo);
        return JSONResult.instance().setData(dataMap);
    }

    @Oauth
    @ResponseBody
    @RequestMapping(value = "/oauth/role/findAll")
    public JSONResult findRoleAll() {
        List<RoleInfo> listRole = this.userInfoService.findAllRole();
        return JSONResult.instance().setData(listRole);
    }

    @Oauth
    @ResponseBody
    @RequestMapping(value = "/oauth/resource/findAll")
    public JSONResult findResourceAll() {
        List<Resource> listResource = this.userInfoService.findAllResource(0L);
        return JSONResult.instance().setData(listResource);
    }

    @ResponseBody
    @RequestMapping(value = "/login")
    public JSONResult login(@RequestBody LoginParam param) {
        try {
            UserLoginAccountType accountType = null;
            if (ValidateUtil.isBlank(param.getLoginAccount())) {
                return JSONResult.instance("empty_mp_or_email", "请输入您的登录手机号或邮箱");
            }
            if (ValidateUtil.isMobile(param.getLoginAccount())) {
                accountType = UserLoginAccountType.mp;
            }
            if (ValidateUtil.isEmail(param.getLoginAccount())) {
                accountType = UserLoginAccountType.email;
            }
            if (accountType == null) {
                return JSONResult.instance("invalid_mp_or_email", "请输入正确的手机号或邮箱");
            }

            if (StringUtils.isBlank(param.getLoginPassword())) {
                return JSONResult.instance("empty_password", "请输入登录密码");
            }

            UserLoginAccount userLoginAccount = this.userInfoService.findLoginAccount(param.getLoginAccount(), accountType);
            if (userLoginAccount == null) {
                return JSONResult.instance("no_found_mp_or_email", "用户名或密码错误，请重新输入");
            } else {
                UserInfo userBaseInfo = this.userInfoService.findUserInfoById(userLoginAccount.getUid());

                UserPassword userPassword = this.userInfoService.findUserPassword(userBaseInfo.getId(), UserPasswdType.login);
                if (userPassword == null) {
                    return JSONResult.instance("no_found_password", "用户名或密码错误，请重新输入");
                }
                UserLoginLog lastLoginLog = this.userInfoService.findLastLogin(userBaseInfo.getId());


                String loginPassword = this.oauthService.genPwd(param.getLoginPassword(), userPassword.getSalt(), true);

                if (loginPassword.equals(userPassword.getPasswd())) {
                    try {
                        this.userInfoService.updateLoginInfo(userBaseInfo.getId(), ServletUtil.getRemoteIp());
                    } catch (Exception e) {
                        logger.warn("save login log error", e);
                    }

                    Date lastLoginTime = lastLoginLog == null ? DateUtil.current() : lastLoginLog.getLoginTime();

                    String sessionId = ServletContext.getSessionId();
                    if (sessionId == null) {
                        sessionId = Token.getToken(ServletContext.getRemoteIp()).toTokenString();
                    }

                    OauthUser oauthUser = OauthUser.instance(userBaseInfo.getId(), userBaseInfo.getNickName(), lastLoginTime, sessionId);
                    stringRedisTemplate.boundValueOps("userInfo").set(JSON.toJSONString(oauthUser));

                    List<Resource> listResource = this.userInfoService.findResourceByUser(userBaseInfo.getId());
                    Set<String> listAuthorities = new HashSet<>();

                    if (listResource != null && !listResource.isEmpty()) {
                        for (Resource resource : listResource) {
                            listAuthorities.add(resource.getAuthority());
                        }
                    }
                    this.oauthService.setAuth(sessionId, oauthUser);
                    this.oauthService.setAuthorities(sessionId, listAuthorities);

                    Map<String, Object> dataMap = new HashMap<>(2);
                    dataMap.put("oauthUser", oauthUser);
                    dataMap.put("authorities", listAuthorities);
                    return JSONResult.instance().setData(dataMap);
                } else {
                    return JSONResult.instance("password_error", "用户名或密码错误，请重新输入");
                }
            }
        } catch (Exception e) {
            logger.error("login error", e);
            return JSONResult.instance("system_error", "系统忙，请稍后再试");
        }
    }

    @ResponseBody
    @RequestMapping(value = "/getOauth")
    public JSONResult getOauth() {
        String sessionId = ServletContext.getSessionId();
        OauthUser oauthUser = this.oauthService.getOAuth(sessionId);
        Set<String> listAuthorities = this.oauthService.getAuthorities(sessionId);
        Map<String, Object> dataMap = new HashMap<>(2);

        dataMap.put("oauthUser", oauthUser);
        dataMap.put("authorities", listAuthorities);
        return JSONResult.instance().setData(dataMap);
    }

    @Oauth
    @ResponseBody
    @RequestMapping(value = "/logout")
    public JSONResult logout() {
        String sessionId = ServletContext.getSessionId();
        this.oauthService.destroy(sessionId);
        return JSONResult.instance().setData(true);
    }

    @Oauth
    @ResponseBody
    @RequestMapping("/modifyPassword")
    public JSONResult modifyPassword(@RequestBody ModifyPasswordParam param) {
        try {
            if (StringUtils.isBlank(param.getOldPassword())) {
                return JSONResult.instance("empty_old_password", "请输入旧的登录密码");
            }
            if (StringUtils.isBlank(param.getNewPassword())) {
                return JSONResult.instance("empty_new_password", "请输入新的登录密码");
            }
            if (!param.getNewPassword().equals(param.getConfirmPassword())) {
                return JSONResult.instance("confirm_password_not_match", "新的登录密码与确认密码不一致");
            }

            String sessionId = ServletContext.getSessionId();
            OauthUser oauthUser = this.oauthService.getOAuth(sessionId);

            UserPassword userPassword = this.userInfoService.findUserPassword(oauthUser.getId(), UserPasswdType.login);
            String oldPassword = this.oauthService.genPwd(param.getOldPassword(), userPassword.getSalt(), true);

            if (oldPassword.equals(userPassword.getPasswd())) {
                String salt = RandCodeUtil.getSalt();
                String loginPassword = this.oauthService.genPwd(param.getNewPassword(), salt, true);

                userPassword.setSalt(salt);
                userPassword.setPasswd(loginPassword);

                this.userInfoService.updateUserPassword(userPassword.getUid(), loginPassword, salt, UserPasswdType.login);
                return JSONResult.instance("success", "修改登录密码成功，下次请使用新的登录密码登录");
            } else {
                return JSONResult.instance("error_old_password", "旧的登录密码不正确，请重新输入");
            }
        } catch (Exception e) {
            logger.error("change password Error", e);
            return JSONResult.instance("system_error").setMessage("系统忙，请稍后再试");
        }
    }

}
